package com.hn.gege.sys.modules.sys.controller;

import cn.hutool.core.util.RandomUtil;
import com.hn.gege.core.util.cache.ICacheUtils;
import com.hn.gege.sys.modules.sys.dto.LoginResultDTO;
import com.hn.gege.sys.modules.sys.dto.RegisterDTO;
import com.hn.gege.sys.modules.sys.entity.User;
import com.hn.gege.sys.conf.security.AdminUserDetails;
import com.hn.gege.sys.modules.sys.service.IEmailService;
import com.hn.gege.sys.modules.sys.service.ILoginService;
import com.hn.gege.sys.modules.sys.service.IUserService;
import com.hn.gege.sys.conf.security.MyUserDetailsService;
import com.hn.gege.core.common.CommonResult;
import com.hn.gege.core.common.MyException;
import com.hn.gege.core.common.ParmException;
import com.hn.gege.core.common.BaseController;
import com.hn.gege.core.util.JwtTokenUtil;
import com.hn.gege.core.util.MD5Util;
import com.hn.gege.core.util.RandImageUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;

@Api(tags = "SysLoginController", description = "登录注册管理")
@RestController
@RequestMapping("/sys/login")
@Validated
public class LoginController extends BaseController {

    @Value("${project.redis-key.email}")
    private String emailKey;
    @Value("${project.redis-key.email-expiration}")
    private long emailExpiration;
    @Value("${project.redis-key.img-captcha}")
    private String imgCaptchaKey;
    @Value("${project.redis-key.codeError}")
    private String codeError;


    private static final String BASE_CHECK_CODES = "qwertyuiplkjhgfdsazxcvbnmQWERTYUPLKJHGFDSAZXCVBNM1234567890";



    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private IUserService userService;
    @Autowired
    private ILoginService loginService;
    @Autowired
    private IEmailService emailService;
    @Autowired
    private MyUserDetailsService userDetailsService;
    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Autowired
    private ICacheUtils cacheUtils;


    @ApiOperation("发送邮件验证码")
    @ApiImplicitParam(name = "email", value = "邮箱", required = true, dataType = "String", paramType = "query")
    @GetMapping("/sendEmail")
    public CommonResult sendEmail(@NotBlank @Email String email, HttpServletRequest request){
        String item = request.getRemoteAddr() + email;
        boolean b = cacheUtils.hHasKey(emailKey, item);
        if (b){
            return CommonResult.failed("验证码已发送,如果没有收到,请稍后重新发送!");
        }

        String code = emailService.loginVerificationCode(email);
        cacheUtils.hset(emailKey, item, code, emailExpiration);
        return  CommonResult.success("成功");
    }

    @ApiOperation("邮箱登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "email", value = "邮箱", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "captcha", value = "验证码", required = true, dataType = "String", paramType = "query")
    })
    @GetMapping("/emailLogin")
    public CommonResult<LoginResultDTO> emailLogin(@NotBlank @Email String email, @NotBlank String captcha, HttpServletRequest request) throws MyException {
        //检验邮箱验证码
        String cheakCaptcha = cheakEmailCaptcha(captcha, request.getRemoteAddr() + email);
        if(cheakCaptcha != null){
            return CommonResult.failed(cheakCaptcha);
        }
        //邮箱用户不存在,添加临时用户
        User user = userService.getByUserName(email);
        if (user == null)
            loginService.addTempUser(email);

        //执行登录授权
        AdminUserDetails userDetails = userDetailsService.loadUserByUsername(email, null);
        User user2 = userDetails.getUser();
        if (! "1".equals(user2.getState())){
            throw new MyException("用户被禁用!");
        }
        String token = jwtTokenUtil.generateToken(userDetails.getUsername(),
                user2.getId(),
                userDetails.getRoleCode(),
                user2.getOrgCode());
        LoginResultDTO loginResultDTO = new LoginResultDTO(token, user.getId(), userDetails.getRoleCode(), user2.getNickname(), user2.getSex(), user2.getHeadImg());
        return  CommonResult.success(loginResultDTO);
    }


    @ApiOperation("注册")
    @PostMapping("/register")
    public CommonResult register(@Validated RegisterDTO registerDTO, BindingResult bindingResult) throws ParmException {
        boolean b = loginService.register(registerDTO);
        if (b){
            return CommonResult.success("成功");
        }
        return CommonResult.failed("失败");
    }

    @ApiOperation("用户名密码登录")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "username", value = "用户名", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "password", value = "密码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "roleCode", value = "登录角色", dataType = "String", paramType = "query"),
    })
    @GetMapping("/login")
    public CommonResult login(@NotBlank String username, @NotBlank String password, String roleCode) throws ParmException {
        User user = userService.getByUserName(username);
        if (user == null)
            return CommonResult.failed("用户名或密码错误");

        boolean matches = passwordEncoder.matches(password, user.getPassword());
        if (! matches)
            return CommonResult.failed("用户名或密码错误");

        //执行登录授权
        AdminUserDetails userDetails = userDetailsService.loadUserByUsername(username, roleCode);
        User user2 = userDetails.getUser();
        if (! "1".equals(user2.getState())){
            return CommonResult.failed("用户被禁用!");
        }
        String token = jwtTokenUtil.generateToken(userDetails.getUsername(),
                user2.getId(),
                userDetails.getRoleCode(),
                user2.getOrgCode());
        LoginResultDTO loginResultDTO = new LoginResultDTO(token, user.getId(), userDetails.getRoleCode(), user2.getNickname(), user2.getSex(), user2.getHeadImg());
        return  CommonResult.success(loginResultDTO);
    }


    /**
     * 后台生成图形验证码 ：有效
     * @param req
     * @param key
     */
    @ApiOperation("获取验证码")
    @GetMapping(value = "/randomImage/{key}")
    public CommonResult<String> randomImage(HttpServletRequest req, @PathVariable String key){
        try {
            String code = RandomUtil.randomString(BASE_CHECK_CODES,4);
            String lowerCaseCode = code.toLowerCase();
            String realKey = MD5Util.MD5Encode(req.getRemoteAddr() + key, "utf-8");
            cacheUtils.hset(imgCaptchaKey, realKey, lowerCaseCode, emailExpiration);
            String base64 = RandImageUtil.generate(code);
            return CommonResult.success(base64);
        } catch (Exception e) {
            e.printStackTrace();
            return CommonResult.failed("获取验证码出错" + e.getMessage());
        }
    }


    /**
     * 校验邮箱验证码
     * @param captcha 验证码
     * @param item 存验证码的,hash中的item
     * @return
     */
    private String cheakEmailCaptcha(String captcha, String item){
        return cheakCaptcha(emailKey, captcha, item);
    }

    /**
     * 校验邮箱验证码
     * @param captcha 验证码
     * @param item 存验证码的,hash中的item
     * @return
     */
    private String cheakImgCaptcha(String captcha, String item){
        return cheakCaptcha(imgCaptchaKey, captcha, item);
    }

    /**
     * 校验验证码
     * @param type 验证码类别
     * @param captcha 验证码
     * @param item 校验码hash中的item
     * @return
     */
    private String cheakCaptcha(String type, String captcha, String item){
        int errorNo = 0;
        //校验验证码是否存在
        boolean b1 = cacheUtils.hHasKey(type, item);
        if ( ! b1){
            return "验证码已失效,请重新发送!";
        }

        //获取验证码校验错误次数
        boolean b = cacheUtils.hHasKey(codeError, item);
        if (b){
            errorNo = cacheUtils.hget(codeError, item);
        }

        //校验错误次数
        String code = cacheUtils.hget(type, item);
        if (! captcha.equals(code)){
            errorNo++;
            if(errorNo >= 3){
                cacheUtils.hdel(codeError, item);
                cacheUtils.hdel(type, item);
                return "验证码错误超过3次,请重新发送验证码!";
            }else {
                cacheUtils.hset(codeError, item, errorNo, Long.valueOf(30));
                return "验证码不正确!";
            }
        }
        return null;
    }

}
